﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net.Sockets;
using System.IO;
using System.Threading;
using System.Data.SqlClient;
using System.Drawing;
using psafth.AMB;
using psafth.FSR.Lapcounter.Sound;
using psafth.FSR.Lapcounter.Properties;
using psafth.AMB.Objects;
using System.Net;
using System.Runtime.Serialization.Formatters.Binary;

namespace psafth.FSR.Lapcounter.UserControls
{
    public partial class RaceControl : UserControl
    {
        #region Private members

        private bool _runTimer = false;
        private DbEntities _db;
        private bool _stopRace = false;

        private int _FinishTimout = 60;
        private bool _noAlarm = true;

        private DataView _raceView = new DataView();

        /// <summary>
        /// Holds the mainform which holds the application and subviews
        /// </summary>
        private MainForm _mForm;

        /// <summary>
        /// AMBListener as backgroundworker to connect to the decoder and read its progress
        /// </summary>
        private AMBListener _backgroundWorker;

        /// <summary>
        /// Default value for the timerlabel
        /// </summary>
        private string _timerValue = "10:00.000";
        /// <summary>
        /// Default value
        /// </summary>
        private int _duration = 10;


        private UdpClient _udpClient;
        private IPAddress _multicastAddress;
        private IPEndPoint _remoteEndpoint;

        private int _currentMouseOverRow = -1;
        private int _selectedRightClickedRowIndex = -1;

        private List<int> _passings = new List<int>();
        /// <summary>
        /// List to hold all drivers of the heat.
        /// </summary>
        private List<RaceCompetitor> _competitors;

        /// <summary>
        /// List to hold all finished drivers.
        /// </summary>
        private List<RaceCompetitor> _finishedCompetitors;

        #endregion

        #region Public members

        /// <summary>
        /// Timestamp when the heat is expected to end (with the timeout).
        /// </summary>
        public DateTime FinishTime
        {
            get;
            set;
        }

        /// <summary>
        /// Timestamp when the heat is expected to end.
        /// </summary>
        public DateTime StopTime
        {
            get;
            set;
        }

        /// <summary>
        /// Timestamp when the heat was started
        /// </summary>
        public DateTime StartTime
        {
            get;
            set;
        }

        /// <summary>
        /// Lastest registered noiselevel from the Decoder. This is reported in statusmessages.
        /// </summary>
        public int DecoderNoise
        {
            get;
            set;
        }

        /// <summary>
        /// Gets the Signal strength threshold. The value that's counts as 100% signal strength.
        /// </summary>
        public int SignalStrengthThreshold
        {
            get
            {
                return (DecoderNoise + 60);
            }
        }

        #endregion

        public RaceControl(Heat h, MainForm m)
        {
            InitializeComponent();

            timerControl.Interval = 10;
            timerControl.Enabled = true;

            _db = new DbEntities();

            _mForm = m;

            _competitors = GetHeatCompetitors(h);

            if (h != null)
            {
                lblHeaderText.Text = h.DisplayTitle;
                _timerValue = h.HeatDuration + ":00.000";
                _duration = h.HeatDuration;
            }
            else
            {
                QuickstartHeatSettingsValue value = QuickstartHeatSettings.GetInput(this);

                lblHeaderText.Text = string.Format("Snabbstart [{0}]", DateTime.Now.ToString("yyyy-MM-dd HH:mm"));
                _timerValue = Properties.Settings.Default.DefaultHeatDuration + ":00.000";
                _duration = Properties.Settings.Default.DefaultHeatDuration;

                if (value.Result == DialogResult.OK && value.Duration >= 0)
                {
                    if (!string.IsNullOrEmpty(value.Heatlabel))
                        lblHeaderText.Text = value.Heatlabel;

                    _timerValue = value.Duration + ":00.000";
                    _duration = value.Duration;

                    h = new Heat() { HeatDuration = _duration, DisplayTitle = lblHeaderText.Text };
                }
            }

            try
            {
                HeatCommand toSend = new HeatCommand() { Heat = new Heat() { DisplayTitle = h.DisplayTitle, HeatDuration = h.HeatDuration }, Competitors = _competitors };

                _mForm.SendToMulticastThread(toSend, MulticastDataType.HeatObject);
            }
            catch (Exception)
            {
            }

            lblPassings.Text = string.Empty;

            DataGridViewTextBoxColumn tb_StartNumber = new DataGridViewTextBoxColumn();
            tb_StartNumber.HeaderText = "Startnummer";
            tb_StartNumber.Name = "Startnumber";
            tb_StartNumber.DataPropertyName = "Startnumber";

            DataGridViewProgressColumn tb_signal = new DataGridViewProgressColumn();
            tb_signal.ProgressBarColor = Color.GreenYellow;
            tb_signal.HeaderText = "Signal";
            tb_signal.Name = "Signal";

            DataGridViewTextBoxColumn tb_voltage = new DataGridViewTextBoxColumn();
            tb_voltage.HeaderText = "Spänning";
            tb_voltage.Name = "Voltage";
            tb_voltage.DataPropertyName = "Voltage";

            DataGridViewTextBoxColumn tb_transponderId = new DataGridViewTextBoxColumn();
            tb_transponderId.HeaderText = "TransponderId";
            tb_transponderId.Name = "TransponderId";
            tb_transponderId.DataPropertyName = "TransponderId";

            DataGridViewTextBoxColumn tb_name = new DataGridViewTextBoxColumn();
            tb_name.HeaderText = "Namn";
            tb_name.Name = "Name";

            DataGridViewTextBoxColumn tb_licence = new DataGridViewTextBoxColumn();
            tb_licence.HeaderText = "Licensnummer";
            tb_licence.Name = "Licence";

            DataGridViewTextBoxColumn tb_laps = new DataGridViewTextBoxColumn();
            tb_laps.HeaderText = "Varv";
            tb_laps.Name = "Laps";

            DataGridViewTextBoxColumn tb_bestlap = new DataGridViewTextBoxColumn();
            tb_bestlap.HeaderText = "Bästa varvtid";
            tb_bestlap.Name = "Bestlap";

            DataGridViewTextBoxColumn tb_lastlap = new DataGridViewTextBoxColumn();
            tb_lastlap.HeaderText = "Senaste varvtid";
            tb_lastlap.Name = "Lastlap";

            dgwRaceTable.Columns.Add(tb_StartNumber);
            dgwRaceTable.Columns.Add(tb_transponderId);
            dgwRaceTable.Columns.Add(tb_name);
            dgwRaceTable.Columns.Add(tb_licence);
            dgwRaceTable.Columns.Add(tb_laps);
            dgwRaceTable.Columns.Add(tb_bestlap);
            dgwRaceTable.Columns.Add(tb_lastlap);
            dgwRaceTable.Columns.Add(tb_signal);
            dgwRaceTable.Columns.Add(tb_voltage);

            List<RaceCompetitor> SortedCompetitors = new List<RaceCompetitor>(_competitors);

            SortedCompetitors.Sort(CompetitorComparison);

            foreach (RaceCompetitor c in SortedCompetitors)
                UpdateDGW(c);

            _backgroundWorker = new AMBListener(Settings.IPAdress, Settings.Port);

            _backgroundWorker.WorkerReportsProgress = true;
            _backgroundWorker.WorkerSupportsCancellation = true;
            _backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
            _backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);

            lblTimer.Text = _timerValue;

            _finishedCompetitors = new List<RaceCompetitor>();

            dgwRaceTable.ClearSelection();
        }

        /// <summary> 
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            try
            {
                this._udpClient.Connect(this._remoteEndpoint);
                this._udpClient.Send(new byte[] { (byte)MulticastDataType.NoRace }, 1);
            }
            catch (Exception)
            {
            }

            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        private List<RaceCompetitor> GetHeatCompetitors(Heat heat)
        {
            List<RaceCompetitor> r = new List<RaceCompetitor>();

            // if Quickstart. Add all known transponders as Racecompetitor.
            if (heat != null && heat.HeatDrivers != null)
            {
                foreach (HeatDriver d in heat.HeatDrivers)
                {
                    r.Add(new RaceCompetitor(d));
                }
            }

            return r;
        }

        /// <summary>
        /// Sets the timer label to the corresponding heat time left. Also control whether or not to finish the race.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void timerControl_Tick(object sender, EventArgs e)
        {
            if (_runTimer)
            {
                TimeSpan s = DateTime.Now.Subtract(StopTime);
                TimeSpan t = DateTime.Now.Subtract(FinishTime);

                TimeSpan n = new TimeSpan(0);

                if (s >= n)
                {
                    if (_noAlarm)
                    {
                        Player.PlaySound(1, 1000, true);
                        _noAlarm = !_noAlarm;
                    }

                    _stopRace = true;
                    lblTimer.ForeColor = Color.Red;
                }

                if (t >= n)
                    FinishRace();

                lblTimer.Text = s.ToString(@"mm\:ss\.fff");
            }
        }

        /// <summary>
        /// Finishes the race by Cancelling the AMBListener thread and closing its connection. 
        /// </summary>
        private void FinishRace()
        {
            // Cancel the AMBListener
            _backgroundWorker.CancelAsync();

            // Stop the timer from counting.
            _runTimer = false;

            // Disable all buttons
            btn_stop.Enabled = false;
            btn_pause.Enabled = false;

            // Fetch the mainform and use it to set all buttons to enabled.
            MainForm m = this.ParentForm as MainForm;
            m.SetAllButtons(true);

            // Click the "print"-button
            btn_print_Click(null, null);

            // Set the foregroundcolor on all cells of the rows of the datagrid to Color.LightGray
            foreach (DataGridViewRow r in dgwRaceTable.Rows)
            {
                r.DefaultCellStyle.ForeColor = Color.LightGray;
            }
        }

        private void btn_StartTimer_Click(object sender, EventArgs e)
        {
            if (!_backgroundWorker.IsBusy)
            {
                _backgroundWorker.RunWorkerAsync(StopTime);
                btn_StartTimer.Enabled = false;
                btn_pause.Enabled = true;
                btn_stop.Enabled = true;
            }
        }

        /// <summary>
        /// Manually add a lap to a competitor.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MenuItem_Add_Click(object sender, EventArgs e)
        {
            // Find the competitor by the row the mouse rightclicked in. 
            RaceCompetitor rc = _competitors.Find(delegate(RaceCompetitor r)
            {
                return r.TransponderId == ulong.Parse(dgwRaceTable.Rows[_selectedRightClickedRowIndex].Cells["TransponderId"].Value.ToString());
            });

            // Show a message to confirm the add.
            if (MessageBox.Show(string.Format("Vill du lägga till 1 varv till förare {0}?", rc.LicenceNumber), "Bekräfta", MessageBoxButtons.YesNo) == DialogResult.Yes)
            {
                // Check if its the competitors first lap to record.
                if (rc.Laps.Count > 0)
                {
                    // if the previous lap passingtime isn't null. Add the lap.
                    if (rc.PreviousLap.PassingTime != null)
                    {
                        // Calculate the laptime.
                        double laptime = (DateTime.Now - rc.PreviousLap.PassingTime).TotalSeconds;

                        // Add a new lap to the competitor
                        rc.Laps.Add(new Lap(laptime, DateTime.Now, 0, 0.0, true));
                    }
                }
                else
                {
                    // In case of the first lap recorded
                    // Calculate the laptime (seconds since the start).
                    double laptime = (DateTime.Now - StartTime).TotalSeconds;

                    // Add a new lap to the competitor
                    rc.Laps.Add(new Lap(laptime, DateTime.Now, 0, 0.0, true));
                }


                // TODO: _stopRace changed to compare time intervals.
                if (DateTime.Now > StopTime)
                {
                    _finishedCompetitors.Add(rc);

                    int index = _competitors.FindIndex(delegate(RaceCompetitor k)
                    {
                        return k.TransponderId == rc.TransponderId;
                    });

                    double stopTime = (rc.PreviousLap.PassingTime - StopTime).TotalSeconds;

                    _competitors[index].EndTime = stopTime;
                }

                // Update the DataGridView
                UpdateDGW(rc);

            }
        }

        /// <summary>
        /// Invalidate the latest lap for a competitor.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MenuItem_Remove_Click(object sender, EventArgs e)
        {
            // Find the competitor by the row the mouse rightclicked in. 
            RaceCompetitor rc = _competitors.Find(delegate(RaceCompetitor r)
            {
                return r.TransponderId == ulong.Parse(dgwRaceTable.Rows[_selectedRightClickedRowIndex].Cells["TransponderId"].Value.ToString());
            });

            // Show a message to confirm the invalidation.
            if (MessageBox.Show(string.Format("Vill du dra av ett varv för förare {0}?", rc.LicenceNumber), "Bekräfta", MessageBoxButtons.YesNo) == DialogResult.Yes)
            {
                // Invalidate the last lap.
                rc.Laps.Last().IsValid = false;

                // Update the DataGridView
                UpdateDGW(rc);
            }
        }

        /// <summary>
        /// Disqualifying a selected competitor
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MenuItem_Disqualify_Click(object sender, EventArgs e)
        {
            // Find the competitor by the row the mouse rightclicked in. 
            RaceCompetitor rc = _competitors.Find(delegate(RaceCompetitor r)
            {
                return r.TransponderId == ulong.Parse(dgwRaceTable.Rows[_selectedRightClickedRowIndex].Cells["TransponderId"].Value.ToString());
            });

            // Show a message to confirm the disqualification
            if (MessageBox.Show(string.Format("Vill du diskvalificera förare {0}?", rc.LicenceNumber), "Bekräfta", MessageBoxButtons.YesNo) == DialogResult.Yes)
            {
                // Invalidate all its laps.
                foreach (Lap l in rc.Laps)
                {
                    l.IsValid = false;
                }

                // Add the driver to the finished drivers.
                _finishedCompetitors.Add(rc);
                rc.EndTime = -1.0;

                // Update the DataGridView
                UpdateDGW(rc);
            }
        }

        private void StartTimer()
        {
            TimeSpan durationLeft = new TimeSpan(0,_duration,0);

            if (!_runTimer && !_backgroundWorker.CancellationPending)
            {
                _runTimer = true;
                // Sounds the alarm.
                Player.PlaySound(1, 1000, true);

                StartTime = DateTime.Now;
                // TODO: Fix this properly.
                if (StopTime.Year < 2000)
                {
                    StopTime = DateTime.Now.AddMinutes(_duration);
                }
                else
                {
                    durationLeft = TimeSpan.Parse("0:" + lblTimer.Text);
                    StopTime = DateTime.Now.Add(durationLeft);
                }

                FinishTime = StopTime.AddSeconds(_FinishTimout);

                _mForm.SendToMulticastThread(new StartCommand() { HeatDurationLeft = durationLeft }, MulticastDataType.Start);
            }
        }

        private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            MainForm m = (MainForm)ParentForm;

            if ((e.Cancelled == true))
            {
                m.SetStatusLabel("User cancelled");
            }

            else if (!(e.Error == null))
            {
                m.SetStatusLabel("Error " + e.Error);
            }

            else
            {
                // TODO: !_stopRace changed to compare time intervals.
                if (DateTime.Now < StopTime)
                {
                    _backgroundWorker.RunWorkerAsync();
                }
                else
                {
                    m.SetStatusLabel("Race finished!");
                }
            }
        }

        private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            try
            {
                var returnObj = e.UserState as ReceiverObject;

                if (returnObj.MessageType == AMBMessageType.STATUS)
                {
                    try
                    {
                        StatusObject obj = new StatusObject(returnObj.Data);

                        StartTimer();

                        DecoderNoise = obj.Noise;

                        _mForm.SetStatusLabel("Connected [" + obj.DecoderId + "]");

                        _mForm.SetAllButtons(false || _backgroundWorker.CancellationPending);

                        _mForm.Update();
                    }
                    catch (InvalidCastException)
                    {
                        //MessageBox.Show(ex.Message, "Fel", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                    catch (Exception)
                    {
                        //MessageBox.Show(ex.Message, "Fel", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
                else if (returnObj.MessageType == AMBMessageType.PASSING)
                {
                    try
                    {
                        PassingObject obj = new PassingObject(returnObj.Data);

                        //Player.PlaySound(0, 100, false);

                        // Update the Statuslabel. Just because you can ;)
                        _mForm.SetStatusLabel("Receiving passing from [" + obj.TransponderId + "]");
                        _mForm.Update();

                        RaceCompetitor Competitor = _competitors.Find(delegate(RaceCompetitor r)
                        {
                            return r.TransponderId == obj.TransponderId;
                        });


                        if (Competitor == null)
                        {
                            Transponder ct = null;
                            Driver cd = null;

                            foreach (Transponder t in _db.Transponders)
                            {
                                if (t.TransponderId == (int)obj.TransponderId)
                                {
                                    ct = t;
                                    cd = t.Owner;

                                    break;
                                }
                            }

                            if (ct != null && cd != null)
                            {
                                Competitor = _competitors.Find(delegate(RaceCompetitor c)
                                {
                                    return c.LicenceNumber == cd.LicenceNumber;
                                });

                                if (Competitor == null)
                                {
                                    Competitor = new RaceCompetitor(cd.FirstName, cd.LastName, cd.LicenceNumber, (ulong)ct.TransponderId, 0);

                                    _competitors.Add(Competitor);
                                }
                            }
                            else
                            {
                                Competitor = new RaceCompetitor("Okänd", "", "", obj.TransponderId, 0);
                                _competitors.Add(Competitor);
                            }
                        }

                        if (Competitor != null)
                        {
                            // TODO: _stopRace changed to compare time intervals.
                            if (obj.PassingTime > StopTime)
                            {
                                RaceCompetitor isFinished = _finishedCompetitors.Find(delegate(RaceCompetitor c)
                                {
                                    return c.TransponderId == Competitor.TransponderId;
                                });

                                if (isFinished != null)
                                    return;
                            }

                            // if, the competitors first lap
                            if (Competitor.Laps.Count < 1)
                            {
                                double LapTime = (obj.PassingTime - this.StartTime).TotalSeconds;

                                if (LapTime < 10)
                                    return;

                                Competitor.Laps.Add(new Lap(LapTime, obj.PassingTime, obj.SignalStrength, 0.0));
                            }
                            else
                            {
                                double lapTime;

                                if (Competitor.PreviousLap.PassingTime != null)
                                {
                                    lapTime = (obj.PassingTime - Competitor.PreviousLap.PassingTime).TotalSeconds;

                                    if (lapTime < 10)
                                        return;

                                    Competitor.Laps.Add(new Lap(lapTime, obj.PassingTime, obj.SignalStrength, 0.0));
                                }
                            }

                            // TODO: _stopRace changed to compare time intervals.
                            if (obj.PassingTime > StopTime)
                            {
                                _finishedCompetitors.Add(Competitor);

                                int index = _competitors.FindIndex(delegate(RaceCompetitor k)
                                {
                                    return k.TransponderId == Competitor.TransponderId;
                                });

                                double stopTime = (Competitor.PreviousLap.PassingTime - StopTime).TotalSeconds;

                                _competitors[index].EndTime = stopTime;
                            }

                            Player.PlaySound(0, 80, false);

                            SetDGWDataSource SetDataSourceDel = UpdateDGW;

                            if (this.dgwRaceTable.InvokeRequired)
                            {
                                this.dgwRaceTable.Invoke(SetDataSourceDel, Competitor);
                            }
                            else
                            {
                                UpdateDGW(Competitor);
                            }

                            if (Competitor.StartNumber > 0)
                            {
                                _passings.Add(Competitor.StartNumber);
                                UpdatePassingsLabel();
                            }
                        }

                        _mForm.SendToMulticastThread(_competitors, MulticastDataType.Competitors);
                    }
                    catch (InvalidCastException)
                    {
                        //throw ex;
                    }
                    catch (Exception)
                    {
                        // TODO: Implement 
                    }
                }
            }
            catch (Exception)
            {
                // TODO: Log. Then nothing.
            }
        }

        private void dgwRaceTable_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                if (_currentMouseOverRow >= 0)
                {
                    _selectedRightClickedRowIndex = _currentMouseOverRow;

                    ContextMenu contextMenu = new ContextMenu();

                    MenuItem mi = new MenuItem("Tillägg: 1 varv", MenuItem_Add_Click);

                    if (!_runTimer)
                        mi.Enabled = false;

                    contextMenu.MenuItems.Add(mi);
                    contextMenu.MenuItems.Add(new MenuItem("Avdrag: 1 varv", MenuItem_Remove_Click));
                    contextMenu.MenuItems.Add(new MenuItem("Diskvalificera", MenuItem_Disqualify_Click));

                    contextMenu.Show(dgwRaceTable, new Point(e.X, e.Y));
                }
            }
        }

        private void dgwRaceTable_CellMouseEnter(object sender, DataGridViewCellEventArgs e)
        {
            _currentMouseOverRow = e.RowIndex;
        }

        private void dgwRaceTable_CellMouseLeave(object sender, DataGridViewCellEventArgs e)
        {
            _currentMouseOverRow = -1;
        }

        private double CalculateSignalStrength(double signal)
        {
            double s = signal / SignalStrengthThreshold;

            if (s <= 0)
                return 0.0;

            return (s * 100.0);
        }


        private delegate void SetDGWDataSource(RaceCompetitor c);

        //Set method invoked by background thread
        private void UpdateDGW(RaceCompetitor c)
        {
            try
            {
                // Find the index of the competitor.
                int index = -1;

                foreach (DataGridViewRow row in dgwRaceTable.Rows)
                {
                    if (row.Cells[1].Value.Equals(c.TransponderId))
                    {
                        index = row.Index;
                    }
                }

                if (index < 0)
                {
                    // Add new row for the competitor
                    dgwRaceTable.Rows.Add(c.StartNumber, c.TransponderId, c.FirstName + " " + c.SurName, c.LicenceNumber, c.Laps.Count, c.BestLap, c.PreviousLap.LapTime, CalculateSignalStrength(c.PreviousLap.SignalStrength));
                }
                else
                {
                    // TODO: _stopRace changed to compare time intervals.
                    if (c.Laps.Count > 0 && c.Laps.Last().PassingTime > StopTime)
                    {
                        dgwRaceTable.Rows[index].DefaultCellStyle.ForeColor = Color.LightGray;
                    }

                    HiglightRow(dgwRaceTable.Rows[index]);

                    dgwRaceTable.Rows[index].Cells[4].Value = c.Laps.Count(l => l.IsValid == true);

                    // TODO: _stopRace changed to compare time intervals.
                    if (c.Laps.Count > 0 && c.Laps.Last().PassingTime > StopTime)
                    {
                        if (c.EndTime < 0)
                        {
                            dgwRaceTable.Rows[index].Cells[4].Value += " (DSQ)";
                        }
                        else
                        {
                            dgwRaceTable.Rows[index].Cells[4].Value += string.Format(" ({0}s)", AMBCalculator.TrimDouble(c.EndTime, 3));
                        }
                    }

                    dgwRaceTable.Rows[index].Cells[5].Value = c.BestLap;
                    dgwRaceTable.Rows[index].Cells[6].Value = c.PreviousLap.LapTime;
                    dgwRaceTable.Rows[index].Cells[7].Value = CalculateSignalStrength(c.PreviousLap.SignalStrength);

                }

                dgwRaceTable.ClearSelection();
                dgwRaceTable.Update();
                dgwRaceTable.ClearSelection();

                // TODO: !_stopRace changed to compare time intervals.
                if (!_stopRace)
                    dgwRaceTable.Sort(dgwRaceTable.Columns["Laps"], ListSortDirection.Descending);

                // TODO: _stopRace changed to compare time intervals.
                if (_stopRace)
                {
                    if (_competitors.Count <= _finishedCompetitors.Count)
                        FinishRace();
                }

                dgwRaceTable.ClearSelection();

                
            }
            catch (Exception)
            {
                // TODO: Log, then nothing.
            }
        }

        private void HiglightRow(DataGridViewRow dataGridViewRow)
        {
            BackgroundWorker bgw = new BackgroundWorker();

            bgw.DoWork += bgw_DoWork;

            bgw.RunWorkerAsync(dataGridViewRow);

        }

        void bgw_DoWork(object sender, DoWorkEventArgs e)
        {
            DataGridViewRow row = (DataGridViewRow)e.Argument;

            row.DefaultCellStyle.Font = new Font(DefaultFont, FontStyle.Bold);

            Thread.Sleep(5000);

            row.DefaultCellStyle.Font = new Font(DefaultFont, FontStyle.Regular);

        }

        private void btn_stop_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Vill du stoppa heatet?", "Stoppa heat", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
            {
                _backgroundWorker.CancelAsync();
                _runTimer = false;
                btn_stop.Enabled = false;
                btn_pause.Enabled = false;
                MainForm m = this.ParentForm as MainForm;

                m.SetAllButtons(true);
            }
        }


        private void UpdatePassingsLabel()
        {
            lblPassings.Text = string.Empty;

            List<int> t = new List<int>(_passings);

            t.Reverse();

            int max = 0;

            foreach (int i in t)
            {
                if (max < 10)
                {
                    lblPassings.Text += string.Format(" {0} ", i);
                    max++;
                }
            }
        }

        
           

        private void btn_print_Click(object sender, EventArgs e)
        {
            ReportControl r = new ReportControl(_competitors, lblHeaderText.Text);
        }

        public static Comparison<RaceCompetitor> CompetitorComparison =
            delegate(RaceCompetitor p1, RaceCompetitor p2)
            {
                return p1.StartNumber.CompareTo(p2.StartNumber);
            };

        private void btn_pause_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Vill du pausa heatet?", "Pausa heat", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
            {
                _backgroundWorker.CancelAsync();
                _runTimer = false;
                btn_stop.Enabled = true;
                btn_pause.Enabled = false;
                btn_StartTimer.Enabled = true;
                MainForm m = this.ParentForm as MainForm;

                //m.SetAllButtons(true);
            }
        }

        private void RaceControl_KeyPress(object sender, KeyPressEventArgs e)
        {
            switch (e.KeyChar)
            {
                case (char)Keys.D1:
                    break;
            }
        }

        private void RaceControl_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.D1:
                    break;
                case Keys.D2:
                    break;
                case Keys.D3:
                    break;
                case Keys.D4:
                    break;
                case Keys.D5:
                    break;
                case Keys.D6:
                    break;
                case Keys.D7:
                    break;
                case Keys.D8:
                    break;
                case Keys.D9:
                    break;
                case Keys.D0:
                    break;
                case Keys.Add:
                    string s = string.Empty;
                    break;
                case Keys.Apps:
                    string t = string.Empty;
                    break;
            }
        }
    }

    public class QuickstartHeatSettings : Form
    {
        private TextBox tbHeatlabel;
        private TextBox tbHeatDuration;
        private Button btnOk;
        private Button btnCancel;
        private Label lblHeader;
        private Label lblLabelDescription;
        private Label lblDurationDescription;

        private QuickstartHeatSettings()
        {
            Bitmap bmp = Resources.icon32x32;
            this.Icon = Icon.FromHandle(bmp.GetHicon());
            this.StartPosition = FormStartPosition.CenterParent;
            this.Height = 160;
            this.Width = 220;

            this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;

            lblHeader = new Label();
            lblHeader.Text = "Snabbstart";

            lblLabelDescription = new Label();
            lblLabelDescription.Text = "Heatnamn:";
            lblLabelDescription.Location = new Point(10, 20);
            lblLabelDescription.Width = 80;

            tbHeatlabel = new TextBox();
            tbHeatlabel.Location = new Point(90, 18);

            lblDurationDescription = new Label();
            lblDurationDescription.Text = "Heatlängd (min):";
            lblDurationDescription.Location = new Point(10, 45);
            lblDurationDescription.Width = 80;

            tbHeatDuration = new TextBox();
            tbHeatDuration.Location = new Point(90, 45);
            tbHeatDuration.KeyDown += new KeyEventHandler(tbInputBox_KeyDown);
            tbHeatDuration.Text = Properties.Settings.Default.DefaultHeatDuration.ToString();

            btnOk = new Button();
            btnOk.Text = "OK";
            btnOk.Location = new Point(10, 90);

            btnCancel = new Button();
            btnCancel.Text = "Avbryt";
            btnCancel.Location = new Point(90, 90);

            btnOk.DialogResult = DialogResult.OK;
            btnCancel.DialogResult = DialogResult.Cancel;

            Controls.Add(lblLabelDescription);
            Controls.Add(tbHeatlabel);
            Controls.Add(btnOk);
            Controls.Add(btnCancel);
            Controls.Add(lblDurationDescription);
            Controls.Add(tbHeatDuration);
        }

        private void tbInputBox_KeyDown(object sender, KeyEventArgs e)
        {

            //Allow navigation keyboard arrows and numpad
            switch (e.KeyCode)
            {
                case Keys.Return:
                    btnOk.PerformClick();
                    break;

                case Keys.Up:
                case Keys.Down:
                case Keys.Left:
                case Keys.Right:
                case Keys.PageUp:
                case Keys.PageDown:
                case Keys.NumPad0:
                case Keys.NumPad1:
                case Keys.NumPad2:
                case Keys.NumPad3:
                case Keys.NumPad4:
                case Keys.NumPad5:
                case Keys.NumPad6:
                case Keys.NumPad7:
                case Keys.NumPad8:
                case Keys.NumPad9:
                    e.SuppressKeyPress = false;
                    return;
                default:
                    break;
            }

            //Block non-number characters
            char currentKey = (char)e.KeyCode;
            bool modifier = e.Control || e.Alt || e.Shift;
            bool nonNumber = char.IsLetter(currentKey) || char.IsSymbol(currentKey) || char.IsWhiteSpace(currentKey) || char.IsPunctuation(currentKey);

            if (!modifier && nonNumber)
                e.SuppressKeyPress = true;

            // Handle pasted Text
            if (e.Control && e.KeyCode == Keys.V)
            {
                //Preview paste data (removing non-number characters)
                string pasteText = Clipboard.GetText();
                string strippedText = "";
                for (int i = 0; i < pasteText.Length; i++)
                {
                    if (char.IsDigit(pasteText[i]))
                        strippedText += pasteText[i].ToString();
                }

                if (strippedText != pasteText)
                {
                    //There were non-numbers in the pasted text
                    e.SuppressKeyPress = true;

                    //OPTIONAL: Manually insert text stripped of non-numbers
                    TextBox me = (TextBox)sender;
                    int start = me.SelectionStart;
                    string newTxt = me.Text;
                    newTxt = newTxt.Remove(me.SelectionStart, me.SelectionLength); //remove highlighted text
                    newTxt = newTxt.Insert(me.SelectionStart, strippedText); //paste
                    me.Text = newTxt;
                    me.SelectionStart = start + strippedText.Length;

                }
                else
                    e.SuppressKeyPress = false;
            }
        }

        public static QuickstartHeatSettingsValue GetInput(IWin32Window owner)
        {
            using (QuickstartHeatSettings values = new QuickstartHeatSettings())
            {
                DialogResult result = values.ShowDialog(owner);

                if (!string.IsNullOrEmpty(values.tbHeatDuration.Text))
                {

                    return new QuickstartHeatSettingsValue
                    {
                        Heatlabel = values.tbHeatlabel.Text,
                        Duration = Convert.ToInt32(values.tbHeatDuration.Text),
                        Result = result
                    };
                }
                else
                {
                    return new QuickstartHeatSettingsValue
                    {
                        Heatlabel = values.tbHeatlabel.Text,
                        Duration = 20,
                        Result = result
                    };
                }
            }
        }
    }

    public class QuickstartHeatSettingsValue
    {
        public string Heatlabel { get; set; }
        public int Duration { get; set; }
        public DialogResult Result { get; set; }
    }
}
